package indi.flynn.zhouyi.log;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;

import indi.flynn.zhouyi.log.enums.BizFlowEnum;
import indi.flynn.zhouyi.log.enums.BizFlowNodeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

/**
 * BizFlowLogger
 */
public class BizFlowLogger {

    private static final Logger logger = LoggerFactory.getLogger("BIZ-FLOW");
    // MDC中的key常量
    private static final String TRACE_ID_KEY = "traceId";
    private static final String FLOW_CODE_KEY = "flowCode";
    private static final String FLOW_BIZ_ID_KEY = "flowBizId";

    /**
     * 初始化流程日志上下文
     *
     * @param bizFlow 业务流程
     * @param bizFlowId 业务流程ID，格式为key1=value1,key2=value2
     */
    public static void initContext(BizFlowEnum bizFlow, BizFlowId bizFlowId) {
        String traceId = UUID.randomUUID().toString().replace("-", "");
        MDC.put(TRACE_ID_KEY, traceId);
        MDC.put(FLOW_CODE_KEY, bizFlow.getCode());
        MDC.put(FLOW_BIZ_ID_KEY, bizFlowId != null ? bizFlowId.toString() : "");
    }

    /**
     * 清理流程日志上下文
     */
    public static void clearContext() {
        MDC.remove(TRACE_ID_KEY);
        MDC.remove(FLOW_CODE_KEY);
        MDC.remove(FLOW_BIZ_ID_KEY);
    }

    /**
     * 记录流程节点日志
     *
     * @param node 流程节点
     * @param result 节点执行结果
     * @param msg 节点执行消息
     * @param content 额外信息
     */
    public static void logNode(BizFlowNodeEnum node, boolean result, String msg, BizLogContent content) {
        String resultStr = result ? "SUCCESS" : "FAIL";
        logger.info("node_code={}|result={}|msg={}|{}",
                node.getCode(),
                resultStr,
                msg != null ? msg : "",
                content != null ? content.toString() : "");
    }


    /**
     * 记录流程节点日志（成功）
     *
     * @param node 流程节点
     * @param msg 节点执行消息
     * @param content 额外信息构建器
     */
    public static void logNodeSuccess(BizFlowNodeEnum node, String msg, BizLogContent content) {
        logNode(node, true, msg, content);
    }

    /**
     * 记录流程节点日志（失败）
     *
     * @param node 流程节点
     * @param msg 节点执行消息
     * @param content 额外信息构建器
     */
    public static void logNodeFail(BizFlowNodeEnum node, String msg, BizLogContent content) {
        logNode(node, false, msg, content);
    }

    /**
     * 记录流程节点日志（成功，无额外信息）
     *
     * @param node 流程节点
     * @param msg 节点执行消息
     */
    public static void logNodeSuccess(BizFlowNodeEnum node, String msg) {
        logNodeSuccess(node, msg, null);
    }


    /**
     * 记录流程节点日志（失败，无额外信息）
     *
     * @param node 流程节点
     * @param msg 节点执行消息
     */
    public static void logNodeFail(BizFlowNodeEnum node, String msg) {
        logNodeFail(node, msg, null);
    }

    public static BizFlowId createBizFlowId(String key, String value) {
        return new BizFlowId(key, value);
    }

    public static BizFlowId createBizFlowId() {
        return new BizFlowId();
    }

    public static BizLogContent createBizLogContent(String key, String value) {
        return new BizLogContent(key, value);
    }

    public static BizLogContent createBizLogContent() {
        return new BizLogContent();
    }

    /**
     * 业务流程ID
     * 用于构造和格式化业务ID，格式为：key1=value1,key2=value2
     * @Author jingxian.lzg
     * @Date 2025/6/25
     */
    public static class BizFlowId {

        private final Map<String, String> params = new LinkedHashMap<>();

        /**
         * 创建空的业务流程ID
         */
        public BizFlowId() {
        }

        /**
         * 创建包含一个键值对的业务流程ID
         *
         * @param key
         *         键
         * @param value
         *         值
         */
        public BizFlowId(String key, String value) {
            addParam(key, value);
        }

        /**
         * 添加参数
         *
         * @param key
         *         键
         * @param value
         *         值
         * @return 当前对象，用于链式调用
         */
        public BizFlowId addParam(String key, String value) {
            if (key != null && value != null) {
                params.put(key, value);
            }
            return this;
        }

        /**
         * 添加参数（值为整数）
         *
         * @param key
         *         键
         * @param value
         *         整数值
         * @return 当前对象，用于链式调用
         */
        public BizFlowId addParam(String key, int value) {
            return addParam(key, String.valueOf(value));
        }

        /**
         * 添加参数（值为长整数）
         *
         * @param key
         *         键
         * @param value
         *         长整数值
         * @return 当前对象，用于链式调用
         */
        public BizFlowId addParam(String key, long value) {
            return addParam(key, String.valueOf(value));
        }

        /**
         * 添加参数（值为布尔值）
         *
         * @param key
         *         键
         * @param value
         *         布尔值
         * @return 当前对象，用于链式调用
         */
        public BizFlowId addParam(String key, boolean value) {
            return addParam(key, String.valueOf(value));
        }

        /**
         * 添加参数（值为对象）
         *
         * @param key
         *         键
         * @param value
         *         对象值
         * @return 当前对象，用于链式调用
         */
        public BizFlowId addParam(String key, Object value) {
            return addParam(key, value != null ? value.toString() : "null");
        }

        /**
         * 获取格式化后的业务ID字符串 格式为：key1=value1|key2=value2
         *
         * @return 格式化后的业务ID字符串
         */
        @Override
        public String toString() {
            if (params.isEmpty()) {
                return "";
            }

            StringBuilder builder = new StringBuilder();
            boolean isFirst = true;

            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (!isFirst) {
                    builder.append("|");
                }
                builder.append(entry.getKey()).append("=").append(entry.getValue());
                isFirst = false;
            }

            return builder.toString();
        }
    }

    /**
     * 业务日志内容
     * 用于构建key=value格式的日志内容
     * @Author jingxian.lzg
     * @Date 2025/6/25
     */
    public static class BizLogContent {

        private final Map<String, String> params = new LinkedHashMap<>();

        /**
         * 创建空的业务日志内容
         */
        public BizLogContent() {
        }

        /**
         * 创建包含一个键值对的业务日志内容
         *
         * @param key 键
         * @param value 值
         */
        public BizLogContent(String key, String value) {
            addParam(key, value);
        }

        /**
         * 添加参数
         *
         * @param key 键
         * @param value 值
         * @return 当前对象，用于链式调用
         */
        public BizLogContent addParam(String key, String value) {
            if (key != null && value != null) {
                params.put(key, value);
            }
            return this;
        }

        /**
         * 添加参数（值为整数）
         *
         * @param key 键
         * @param value 整数值
         * @return 当前对象，用于链式调用
         */
        public BizLogContent addParam(String key, int value) {
            return addParam(key, String.valueOf(value));
        }

        /**
         * 添加参数（值为长整数）
         *
         * @param key 键
         * @param value 长整数值
         * @return 当前对象，用于链式调用
         */
        public BizLogContent addParam(String key, long value) {
            return addParam(key, String.valueOf(value));
        }

        /**
         * 添加参数（值为布尔值）
         *
         * @param key 键
         * @param value 布尔值
         * @return 当前对象，用于链式调用
         */
        public BizLogContent addParam(String key, boolean value) {
            return addParam(key, String.valueOf(value));
        }

        /**
         * 添加参数（值为对象）
         *
         * @param key 键
         * @param value 对象值
         * @return 当前对象，用于链式调用
         */
        public BizLogContent addParam(String key, Object value) {
            return addParam(key, value != null ? value.toString() : "null");
        }

        /**
         * 获取格式化后的内容字符串
         * 格式为：key1=value1|key2=value2
         *
         * @return 格式化后的内容字符串
         */
        @Override
        public String toString() {
            if (params.isEmpty()) {
                return "";
            }

            StringBuilder builder = new StringBuilder();
            boolean isFirst = true;

            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (!isFirst) {
                    builder.append("|");
                }
                builder.append(entry.getKey()).append("=").append(entry.getValue());
                isFirst = false;
            }

            return builder.toString();
        }
    }
}
